﻿using CSSD.Server.DataModel.RoutineBusinessModel;
using DapperEx;
using Dapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using EmitMapper;

namespace ExtensionHelper
{
    [TestClass]
    public class UnitExtension
    {
        public string connectionName = "strSqlCe";
        public string conn = "LocalSqlServer1";
        public DbBase CreateDbBase()
        {
            return new DbBase(conn);
        }

        [TestMethod]
        public void TestConvertList()
        {
            //目的：测试普通DataTable与Emit转换为实体类的效率
            //结果：Emit效率大概是普通转换的20倍
            for (int i = 0; i < 100; i++)
            {
                DataTable dt = CreateDbBase().DbConnecttion.QueryDataTable(@"select * from TrunAroundJournal");

                Stopwatch sw = new Stopwatch();
                sw.Start();

                int count = dt.ToList<TrunAroundJournalModel>().Count;
                sw.Stop();
                System.Diagnostics.Debug.WriteLine("1----查询总数:" + count + " ;  ---" + sw.ElapsedMilliseconds);


                Stopwatch sw2 = new Stopwatch();
                sw2.Start();

                int count1 = DataRowExtension.ToList<TrunAroundJournalModel>(dt).Count;
                sw2.Stop();
                System.Diagnostics.Debug.WriteLine("2----查询总数:" + count + " ;  ---" + sw2.ElapsedMilliseconds);
            }
        }

        [TestMethod]
        public void TestConvertDataTable()
        {
            //目的：测试list转换DataTable与直接查询DataTable的效率
            //结果：直接查询大概是间接转换的2倍
            for (int i = 0; i < 100; i++)
            {
                IEnumerable<TrunAroundJournalModel> modelList = CreateDbBase().DbConnecttion.Query<TrunAroundJournalModel>(@"select top 1000 * from TrunAroundJournal");

                Stopwatch sw1 = new Stopwatch();
                sw1.Start();

                int count1 = modelList.ToDataTable<TrunAroundJournalModel>().Rows.Count;
                sw1.Stop();
                System.Diagnostics.Debug.WriteLine("1----查询总数:" + count1 + " ;  ---" + sw1.ElapsedMilliseconds);

                Stopwatch sw2 = new Stopwatch();
                sw2.Start();

                DataTable dt = CreateDbBase().DbConnecttion.QueryDataTable(@"select top 1000 * from TrunAroundJournal");
                int count2 = dt.Rows.Count;
                sw2.Stop();
                System.Diagnostics.Debug.WriteLine("2----查询总数:" + count2 + " ;  ---" + sw2.ElapsedMilliseconds);

            }
        }
    }

    public static class DataRowExtension
    {
        /// <summary>
        /// 根据实体类集合得到表结构
        /// </summary>
        /// <param name="model">实体类</param>
        /// <returns></returns>
        public static DataTable ListToDataTable<T>(this IList<T> list)
        {
            DataTable dataTable = new DataTable();
            try
            {
                Type columnType = null;
                foreach (PropertyInfo propertyInfo in list[0].GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase))
                {
                    columnType = propertyInfo.PropertyType;
                    if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        // If it is NULLABLE, then get the underlying type. eg if "Nullable<int>" then this will return just "int"
                        columnType = propertyInfo.PropertyType.GetGenericArguments()[0];
                    }
                    dataTable.Columns.Add(new DataColumn(propertyInfo.Name, columnType));
                }
                foreach (T model in list)
                {
                    DataRow dataRow = dataTable.NewRow();
                    foreach (PropertyInfo propertyInfo in model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase))
                    {
                        dataRow[propertyInfo.Name] = propertyInfo.GetValue(model, null) ?? DBNull.Value;
                    }
                    dataTable.Rows.Add(dataRow);
                }
            }
            catch { }
            return dataTable;
        }
        public static List<T> ToList<T>(DataSet ds) where T : new()
        {
            if (ds == null || ds.Tables.Count == 0)
            {
                return new List<T>();
            }

            return ToList<T>(ds.Tables[0]);
        }
        public static List<T> ToList<T>(DataTable dt) where T : new()
        {
            if (dt == null || dt.Rows.Count == 0)
            {
                return new List<T>();
            }
            List<T> modelList = new List<T>();
            foreach (DataRow dr in dt.Rows)
            {
                modelList.Add(ToEntity<T>(dr));
            }
            return modelList;
        }
        public static T ToEntity<T>(DataRow dr) where T : new()
        {
            T model = new T();
            try
            {
                if (dr != null)
                {
                    string value = null;
                    foreach (PropertyInfo pro in model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase))
                    {
                        value = (!dr.Table.Columns.Contains(pro.Name) || string.IsNullOrEmpty(dr[pro.Name] + "")) ? "" : (dr[pro.Name] + "");
                        if (!pro.PropertyType.IsGenericType)
                        {
                            //非泛型
                            pro.SetValue(model, string.IsNullOrEmpty(value) ? null : Convert.ChangeType(value, pro.PropertyType), null);
                        }
                        else
                        {
                            //泛型Nullable<>
                            Type genericTypeDefinition = pro.PropertyType.GetGenericTypeDefinition();
                            if (genericTypeDefinition == typeof(Nullable<>))
                            {
                                pro.SetValue(model, string.IsNullOrEmpty(value) ? null : Convert.ChangeType(value, Nullable.GetUnderlyingType(pro.PropertyType)), null);
                            }
                        }
                    }
                }
            }
            catch { }
            return model;
        }
    }
}
